package com.guanyu.u2cache.aop;

import cn.hutool.core.util.ObjectUtil;
import com.guanyu.u2cache.annotation.U2CacheEvict;
import com.guanyu.u2cache.cache.CacheOperate;
import com.guanyu.u2cache.enums.CacheType;
import com.guanyu.u2cache.expression.CacheOperationExpressionEvaluator;
import com.guanyu.u2cache.expression.GeneratorTransfer;
import com.guanyu.u2cache.util.MethodUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author zhouyunjian
 * @date 2023/10/27 17:09
 **/
@Slf4j
@Aspect
@Component
public class U2CacheEvictAop implements ApplicationContextAware {
    @Resource
    private CacheOperate cacheOperate;
    private ApplicationContext applicationContext;
    private final GeneratorTransfer transfer = new GeneratorTransfer();
    private KeyGenerator keyGenerator = new SimpleKeyGenerator();

    @Pointcut("@annotation(com.guanyu.u2cache.annotation.U2CacheEvict)")
    public void cache() {
    }


    /**
     * 缓存环绕通知：
     * 缓存清空处理
     *
     * @param joinPoint
     */
    @Around("cache()")
    @SneakyThrows
    public void around(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        U2CacheEvict cacheEvict = AnnotationUtils.getAnnotation(signature.getMethod(), U2CacheEvict.class);
        String[] eventNames = cacheEvict.cacheNames();
        CacheType cacheType = cacheEvict.cacheType();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();
        //KeyGenerator keyGenerator = new SimpleKeyGenerator();//SpringUtil.getBean(KeyCacheConfig.keyName, KeyGenerator.class);
        String key = transfer.generateKey(new CacheOperationExpressionEvaluator(), keyGenerator, cacheEvict.key(), MethodUtil.getSpecificmethod(joinPoint), args, target).toString();
        log.info("【{缓存清理}】进入前置name[{}]key[{}]缓存策略[{}]缓存事件[{}]", eventNames, key, cacheType, cacheEvict.listenEventName());
        try {
            joinPoint.proceed();
            if (ObjectUtil.isNotEmpty(cacheEvict.listenEventName())) {
                cacheOperate.clear(cacheEvict.listenEventName(), cacheType);
            } else {
                cacheOperate.clear(eventNames, key, cacheType);
            }
        } catch (Throwable e) {
            log.error("【{缓存清理}】name[{}]缓存[{}]key[{}]处理出异常", eventNames, key, e);
        }
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
